package com.apache.poi.word.utils;

import com.deepoove.poi.xwpf.NiceXWPFDocument;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.apache.poi.util.Units;
import org.apache.poi.xwpf.usermodel.Document;
import org.apache.poi.xwpf.usermodel.XWPFDocument;
import org.apache.poi.xwpf.usermodel.XWPFParagraph;
import org.apache.poi.xwpf.usermodel.XWPFRun;
import org.apache.xmlbeans.XmlException;
import org.openxmlformats.schemas.drawingml.x2006.main.CTGraphicalObject;
import org.openxmlformats.schemas.drawingml.x2006.wordprocessingDrawing.CTAnchor;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTDrawing;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTFonts;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.CTRPr;
import org.springframework.core.io.ClassPathResource;

import javax.validation.constraints.NotNull;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

/**
 * @Author: HUANG GY.
 * @Date: 2022/2/9 14:28
 * @Description: com.apache.poi.word.utils
 */
@Slf4j
public class WordUtil {

    /**
     *  获取resources目录下的文件的文件流
     * @param pathName
     * @return
     */
    public static InputStream getFileInputStream(@NotNull String pathName){
        log.debug("获取resources目录下的文件的文件流pathName={}",pathName);
        ClassPathResource imageResource = new ClassPathResource(pathName);
        InputStream inputStream = null ;
        try {
            inputStream = imageResource.getInputStream();
        } catch (IOException e) {
            log.error("获取文件流失败",e);
            throw new IllegalArgumentException("获取文件失败");
        }
        return inputStream;
    }

    /**
     *  文件流2NiceXWPFDocument
     * @param inputStream
     * @return
     */
    public static NiceXWPFDocument in2niceDoc(InputStream inputStream){
        log.debug("文件流2docinputStream={}",inputStream);
        NiceXWPFDocument doc = null ;
        try {
            doc = new NiceXWPFDocument(inputStream);
        } catch (IOException e) {
            log.error("in2niceDoc，获取word合并文档失败",e);
            throw new IllegalArgumentException("获取word合并文档失败");
        }
        return doc;
    }

    /**
     *  文件2NiceXWPFDocument
     * @param pathName
     * @return
     */
    public static NiceXWPFDocument in2niceDoc(String pathName){
        log.debug("文件2pathName={}",pathName);

        InputStream inputStream = getFileInputStream(pathName);
        NiceXWPFDocument doc =  in2niceDoc(inputStream);
        return doc;
    }

    /**
     *  文件2NiceXWPFDocument,新取一页
     * @param pathName
     * @return
     */
    public static NiceXWPFDocument in2niceDocPage(String pathName){
        log.debug("文件2pathName={}",pathName);
        InputStream inputStream = getFileInputStream(pathName);
        NiceXWPFDocument doc =  in2niceDoc(inputStream);
        BreakTrue(doc) ;
        return doc;
    }

    /**
     *  创建文档
     * @return
     */
    public static XWPFDocument createDoc(){

        return new XWPFDocument();
    }


    /**
     *  创建文档
     * @return
     */
    public static NiceXWPFDocument createDocNice(){

        return new NiceXWPFDocument();
    }


    /**
     *  读取文档
     * @return
     */
    public static XWPFDocument readDoc(String pathName){
        XWPFDocument doc = null ;
        try {
            doc = new XWPFDocument(new FileInputStream(pathName));
        } catch (IOException e) {
            log.error("readDoc，读取文档失败，文档不存在",e);
            throw new IllegalArgumentException("读取文档失败，文档不存在pathName="+pathName);
        }
        return doc;
    }

    /**
     *  读取文档
     * @return
     */
    public static XWPFDocument readDoc(InputStream in){
        XWPFDocument doc = null ;
        try {
            doc = new XWPFDocument(in);
        } catch (IOException e) {
            log.error("readDoc，读取文档失败，文档不存在",e);
            throw new IllegalArgumentException("读取文档失败，文档不存在in="+in);
        }
        return doc;
    }

    private static final int WIDTH = 596 ;
    private static final int HIGH = 840 ;
    private static final int LEFT = -89 ;
    private static final int TOP = -71 ;

    /**
     *  增加一页封面
     * @param doc 文档
     * @param in  图片文件流
     */
    private static void coverPage(XWPFDocument doc,InputStream in,Integer width,Integer high,Integer left,Integer top) throws IOException, InvalidFormatException {
        //创建段落
        XWPFParagraph paragraph = doc.createParagraph();
        //创建基本组成单元
        XWPFRun run = paragraph.createRun();
        //添加图片
        run.addPicture(in, Document.PICTURE_TYPE_PNG, "TEST", Units.toEMU((null==width)?WIDTH:width), Units.toEMU((null==high)?HIGH:high));
        //设置图片属性
        picAttribute(run,0,width,high,left,top);
        //增加一个空白页
        BreakTrue(doc) ;
        //关闭流
        close(in);
    }

    /**
     *  设置图片属性
     * @param run
     * @param width
     * @param high
     * @param left
     * @param top
     */
    public static void picAttribute(XWPFRun run,Integer index,Integer width,Integer high,Integer left,Integer top){
        //设置图片属性
        CTDrawing drawing = run.getCTR().getDrawingArray(index);
        CTGraphicalObject graphicalobject = drawing.getInlineArray(0).getGraphic();
        CTAnchor anchor = WordUtil.getAnchorWithGraphic(graphicalobject, "TEST1",
                //图片大小
                Units.toEMU((null==width)?WIDTH:width), Units.toEMU((null==high)?HIGH:high),
                //相对当前段落位置 需要计算段落已有内容的左偏移
                Units.toEMU((null==left)?LEFT:left), Units.toEMU((null==top)?TOP:top), false);
        //添加浮动属性
        drawing.setAnchorArray(new CTAnchor[]{anchor});
        //删除行内属性
        drawing.removeInline(0);
    }



    /**
     * 增加包含封面的doc
     * @param picInputstreamList
     */
    public static NiceXWPFDocument coverPage(List<InputStream> picInputstreamList) throws IOException, InvalidFormatException {
        NiceXWPFDocument doc = createDocNice();
        for (InputStream in : picInputstreamList) {
//            coverPage(doc, in, WIDTH, HIGH, LEFT, TOP);
        }
        return doc;
    }



    /**
     *  通过xml设置图片属性
     * @param ctGraphicalObject 图片数据
     * @param deskFileName      图片描述
     * @param width             宽
     * @param height            高
     * @param leftOffset        水平偏移 left
     * @param topOffset         垂直偏移 top
     * @param behind            文字上方，文字下方
     * @return
     * @throws Exception
     */
    public static CTAnchor getAnchorWithGraphic(CTGraphicalObject ctGraphicalObject,
                                                String deskFileName, int width, int height,
                                                int leftOffset, int topOffset, boolean behind) {
        //图片对应的xml，修改关键参数
        String anchorXML =
                "<wp:anchor xmlns:wp=\"http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing\" "
                        + "simplePos=\"0\" relativeHeight=\"0\" behindDoc=\"" + ((behind) ? 1 : 0) + "\" locked=\"0\" layoutInCell=\"1\" allowOverlap=\"1\">"
                        + "<wp:simplePos x=\"0\" y=\"0\"/>"
                        + "<wp:positionH relativeFrom=\"column\">"
                        + "<wp:posOffset>" + leftOffset + "</wp:posOffset>"
                        + "</wp:positionH>"
                        + "<wp:positionV relativeFrom=\"paragraph\">"
                        + "<wp:posOffset>" + topOffset + "</wp:posOffset>" +
                        "</wp:positionV>"
                        + "<wp:extent cx=\"" + width + "\" cy=\"" + height + "\"/>"
                        + "<wp:effectExtent l=\"0\" t=\"0\" r=\"0\" b=\"0\"/>"
                        + "<wp:wrapNone/>"
                        + "<wp:docPr id=\"1\" name=\"Drawing 0\" descr=\"" + deskFileName + "\"/><wp:cNvGraphicFramePr/>"
                        + "</wp:anchor>";

        CTDrawing drawing = null;
        try {
            //重新刷新xml对应的组件
            drawing = CTDrawing.Factory.parse(anchorXML);
        } catch (XmlException e) {
            log.error("图片xml修改错误",e);
            throw new IllegalArgumentException("图片xml修改错误");
        }
        CTAnchor anchor = drawing.getAnchorArray(0);
        anchor.setGraphic(ctGraphicalObject);
        return anchor;
    }

    /**
     *  新增一个空白页
     * @param doc
     */
    private static void BreakTrue(XWPFDocument doc){
        doc.createParagraph().setPageBreak(Boolean.TRUE);
    }

    /**
     *  设置字体样式
     * @param r1
     * @param font
     * @param fontSize
     */
    public static void setXWPFRunStyle(XWPFRun r1,String font,int fontSize) {
        r1.setFontSize(fontSize);
        CTRPr rpr = r1.getCTR().isSetRPr() ? r1.getCTR().getRPr() : r1.getCTR().addNewRPr();
        CTFonts fonts =  rpr.addNewRFonts();
        fonts.setAscii(font);
        fonts.setEastAsia(font);
        fonts.setHAnsi(font);
    }

    /**
     *  关闭流
     * @param in
     */
    public static void close(InputStream in){
        if (in != null) {
            try {
                in.close();
            } catch (IOException e) {
                log.error("流关闭失败",e);
            }
        }
    }

    /**
     * 关闭流
     * @param inList
     */
    public static void close(List<InputStream> inList){
        for (InputStream in : inList) {
            close(in) ;
        }
    }

}
